<template>
    <div class="scanner-container">
        <video ref="videoRef" class="video-preview"></video>
        <div class="scan-overlay"></div>
        <div v-if="statusText" class="status">{{ statusText }}</div>
        <button @click="switchCamera" class="camera-switch">切换摄像头1</button>
    </div>
</template>

<script setup lang="ts">
import {ref, onMounted, onBeforeUnmount} from 'vue';
import {BrowserMultiFormatReader, type Result} from '@zxing/library';
import {showDialog} from "vant";

const emit = defineEmits<{
    (e: 'scan-success', isbn: string): void
    (e: 'scan-error', error: Error): void
}>();

const videoRef = ref<HTMLVideoElement | null>(null);
// 使用更长的超时时间初始化读取器

const codeReader = new BrowserMultiFormatReader(undefined, 5000);
const statusText = ref<string>('正在初始化摄像头...');
let scanTimer: number | null = null;

// ISBN校验函数
const validateISBN = (code: string): boolean => {
    if (code.length !== 13 && code.length !== 10) return false;
    // 这里可以添加更详细的校验逻辑
    return /^\d+$/.test(code);
};
// 添加节流函数
let isScanning = false;
// 开始扫描
const startScan = async () => {
    try {
        // 更新状态文本
        statusText.value = '正在获取摄像头列表...';
        console.log('开始获取摄像头设备列表');
        const devices = await codeReader.listVideoInputDevices();
        console.log('可用摄像头设备:', devices);
        statusText.value = '正在获取摄像头列表...222';
        if (!devices || devices.length === 0) {
            throw new Error('未检测到摄像头设备');
        }
        const deviceId = devices[0].deviceId;
        statusText.value = '正在启动摄像头...';
        let constraints;
        // 在startScan中使用
        const backCameraId = await getBackCamera();
        if (backCameraId) {
            constraints = {
                video: {
                    deviceId: {exact: backCameraId},
                    width: {ideal: 640},
                    height: {ideal: 360}
                }
            };
        } else {
            constraints = {
                video: {
                    deviceId: deviceId,
                    facingMode: 'environment',  // 使用字符串值而不是exact约束，增加兼容性
                    width: {ideal: 640},
                    height: {ideal: 360}
                }
            };
        }

        let stream
        try {
            stream = await navigator.mediaDevices.getUserMedia(constraints);
            console.log('成功获取媒体流');
        } catch (error) {
            if (error instanceof DOMException && error.name === 'NotAllowedError') {
                console.error('用户拒绝了摄像头权限');
                emit('scan-error', new Error('用户拒绝了摄像头权限'));
                showDialog({
                    message: '未获得摄像头调用权限，无法扫描。',
                }).then(() => {
                    // on close
                });
                return;
            }
            throw error;
        }

        if (videoRef == null || !videoRef.value) {
            throw new Error('视频元素未初始化');
        }
        videoRef.value.srcObject = stream;
        videoRef.value.onloadedmetadata = () => {
            console.log('视频元数据已加载');
            statusText.value = '摄像头已就绪，正在扫描...';
            // 确保视频播放成功后再启动扫描
            videoRef.value.play().then(() => {
                // animationFrameId = requestAnimationFrame(scanFrame);
            }).catch(err => console.error('视频播放失败:', err));
        };
    } catch (error) {
        console.error('摄像头初始化失败:', error);
    }
};

let lastScanTime = 0;
let animationFrameId: number | null = null;
const SCAN_INTERVAL = 2000; // 2秒扫描一次
const scanFrame = async (timestamp: number) => {
    // 如果上一次扫描还未完成，则跳过本次扫描
    if (isScanning) {
        console.log('上一次扫描尚未完成，跳过本次扫描');
        return;
    }
    // 检查是否到达扫描间隔
    if (timestamp - lastScanTime >= SCAN_INTERVAL) {
        lastScanTime = timestamp;
        // 扫描逻辑...
        if (!videoRef.value || !videoRef.value.srcObject) {
            console.warn('视频元素或媒体流不存在，跳过扫描');
        } else {
            try {
                isScanning = true;
                const result = await codeReader.decodeOnce(videoRef.value);
                if (result && validateISBN(result.getText())) {
                    console.log('成功扫描到ISBN:', result.getText());
                    emit('scan-success', result.getText());
                    stopScan();
                    return; // 扫描成功后停止动画帧
                }
            } catch (error) {
                console.log('未识别到条码或ISBN无效:', error);
            } finally {
                isScanning = false;
            }
        }
    }
    // 继续下一帧
    animationFrameId = requestAnimationFrame(scanFrame);
};

const getBackCamera = async () => {
    const devices = await navigator.mediaDevices.enumerateDevices();
    const videoDevices = devices.filter(device => device.kind === 'videoinput');
    // 尝试找到后置摄像头
    const backCamera = videoDevices.find(device =>
        device.label.toLowerCase().includes('back') ||
        device.label.toLowerCase().includes('rear') ||
        device.label.toLowerCase().includes('环境') ||
        device.label.toLowerCase().includes('后置')
    );
    return backCamera ? backCamera.deviceId : null;
};

// 添加摄像头切换功能
const isFrontCamera = ref(false);

const switchCamera = async () => {
    // 先停止当前摄像头
    stopScan();
    // 切换摄像头标志
    isFrontCamera.value = !isFrontCamera.value;
    // 使用新的摄像头设置重新启动
    const facingMode = isFrontCamera.value ? 'user' : 'environment';
    try {
        const stream = await navigator.mediaDevices.getUserMedia({
            video: {facingMode: {exact: facingMode}}
        });

        if (videoRef.value) {
            videoRef.value.srcObject = stream;
            // ... 其余代码 ...
            videoRef.value.onloadedmetadata = () => {
                console.log('视频元数据已加载');
                statusText.value = '摄像头已就绪，正在扫描...';
                // 确保视频播放成功后再启动扫描
                videoRef.value.play().then(() => {
                    console.log('视频播放已开始');
                    scanTimer = window.setInterval(async () => {
                        if (!videoRef.value || !videoRef.value.srcObject) {
                            console.warn('视频元素或媒体流不存在，跳过扫描');
                            return;
                        }
                        // 检查媒体流是否活动
                        const stream = videoRef.value.srcObject as MediaStream;
                        if (stream.getTracks().length === 0 || stream.getTracks().every(track => track.readyState === 'ended')) {
                            console.warn('媒体流已中断，停止扫描');
                            stopScan();
                            return;
                        }

                        try {
                            const result: Result = await codeReader.decodeOnce(videoRef.value);
                            if (result && validateISBN(result.getText())) {
                                console.log('成功扫描到ISBN:', result.getText());
                                emit('scan-success', result.getText());
                                stopScan();
                            }
                        } catch (error) {
                            console.log('未识别到条码或ISBN无效:', error);
                        }
                    }, 1000);
                }).catch(err => console.error('视频播放失败:', err));
            };
        }
    } catch (error) {
        console.error('切换摄像头失败:', error);
    }
};

// 停止扫描
const stopScan = () => {
    if (animationFrameId !== null) {
        cancelAnimationFrame(animationFrameId);
        animationFrameId = null;
        console.log('动画帧已取消');
    }
    console.log('正在停止扫描...');
    // 清除扫描定时器
    if (scanTimer) {
        clearInterval(scanTimer);
        scanTimer = null;
        console.log('扫描定时器已清除');
    }
    // 停止所有媒体轨道
    if (videoRef.value?.srcObject) {
        // 释放 codeReader 资源
        try {
            codeReader.reset();
            console.log('条码读取器已重置');
        } catch (error) {
            console.error('重置条码读取器时出错:', error);
        }
        try {
            const stream = videoRef.value.srcObject as MediaStream;
            const tracks = stream.getTracks();
            console.log(`停止 ${tracks.length} 个媒体轨道`);
            tracks.forEach(track => {
                track.stop();
                console.log(`已停止轨道: ${track.kind}`);
            });
            // 清除视频源
            videoRef.value.srcObject = null;
            console.log('视频源已清除');
        } catch (error) {
            console.error('停止媒体轨道时出错:', error);
        }
    } else {
        console.log('没有活动的媒体流需要停止');
    }
    statusText.value = '扫描已停止';
};

// 组件挂载时初始化摄像头
onMounted(() => {
    console.log('组件已挂载，准备初始化摄像头');
    try {
        // 使用setTimeout确保DOM完全渲染后再初始化摄像头
        setTimeout(() => {
            if (!videoRef.value) {
                console.error('视频元素未正确绑定');
                return;
            }
            startScan().catch(error => {
                console.error('摄像头初始化失败:', error);
                statusText.value = `初始化失败: ${error instanceof Error ? error.message : '未知错误'}`;
            });
        }, 300);
    } catch (error) {
        console.error('挂载阶段出错:', error);
    }
});

// 组件卸载前释放摄像头资源
onBeforeUnmount(() => {
    console.log('组件即将卸载，释放摄像头资源');
    try {
        stopScan();
    } catch (error) {
        console.error('卸载阶段释放资源出错:', error);
    }
});
</script>

<style scoped>
.scanner-container {
    position: relative;
    width: 100%;
    max-width: 640px;
    margin: 0 auto;
}

.video-preview {
    width: 100%;
    height: auto;
    background: #000;
}

.scan-overlay {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 70%;
    height: 20%;
    border: 3px solid #4CAF50;
    box-shadow: 0 0 20px rgba(76, 175, 80, 0.5);
}

.status {
    position: absolute;
    bottom: 20px;
    width: 100%;
    text-align: center;
    color: #fff;
    font-size: 16px;
    text-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
}
</style>
